import anime from 'animejs'
import { edgeConfig } from '../config/edgeConfig'
import { sizeConfig } from '../config/sizeConfig'
import { BoolType, IDataValue, IModuleWithState } from '../types'
import {
    createDataValue,
    getCenterPoint,
    setDomBoolVal,
    toBinaryStr,
} from '../utils'
import { bus2, bus3, bus4 } from './bus'
import { ram } from './ram'

interface IMultiplexer31State {
    s1: BoolType
    s2: BoolType
    value: number
}

interface IMultiplexer31 extends IModuleWithState<IMultiplexer31State> {
    dataItem: IDataValue<number> | null
    animation: () => Promise<void>
}

/**
 * multiplexer31 3-1多路复用器模块
 */
export const multiplexer31: IMultiplexer31 = {
    name: 'multiplexer31',
    dataItem: null,
    state: {
        s2: 0,
        s1: 0,
        value: -1,
    },
    async setState(prop, value) {
        if (this.state[prop] === value) return
        if (prop === 's1' || prop === 's2') {
            this.state[prop] = value
            setDomBoolVal(prop, this.state[prop] as BoolType)
        }
        this.change!()
        return
    },
    async change() {
        // 在数据变化时
        const m31BottomCenterPoint = getCenterPoint(
            sizeConfig.multiplexer31,
            'bottom'
        )
        const s = (this.state.s2 << 1) | this.state.s1
        let data = bus2.getData()
        if (s === 1) {
            // 从1号口读取数据，送到输出
            data = bus3.getData()
        } else if (s === 2) {
            // 从2号口读取数据，送到输出
            m31BottomCenterPoint.x += sizeConfig.multiplexer31.width / 6
            data = bus4.getData()
        } else {
            m31BottomCenterPoint.x -= sizeConfig.multiplexer31.width / 6
        }
        if (this.state.value === data) return
        this.state.value = data
        const text = toBinaryStr(data)
        if (this.dataItem === null) {
            this.dataItem = createDataValue(data, text, m31BottomCenterPoint)
        }
        this.dataItem.setText(text)
        this.dataItem.setPosition(m31BottomCenterPoint)
        return this.animation()
    },
    async animation() {
        // 开始动画，先移动到中间，然后移动到输出
        const timeline = anime.timeline({
            targets: this.dataItem!.dom,
            easing: 'linear',
            duration: (edgeConfig.time.rise + edgeConfig.time.high) * 0.05,
        })
        const m21CenterPoint = getCenterPoint(sizeConfig.multiplexer31)
        const ramBottomCenterPoint = getCenterPoint(sizeConfig.ram, 'bottom')
        timeline
            .add({
                translateX: m21CenterPoint.x,
                translateY: m21CenterPoint.y - 10,
            })
            .add({
                translateX: ramBottomCenterPoint.x,
                translateY: ramBottomCenterPoint.y,
                complete: () => {
                    ram.setState('selAddr', this.state.value)
                },
            })
        return timeline.finished
    },
    init() {
        // 设置s1的初始值
        setDomBoolVal('s1', this.state.s1)
        // 设置s2的初始值
        setDomBoolVal('s2', this.state.s2)
        this.change!()
    },
}
